:- dynamic(header/1,
	   fpam/1,
	   fpa/1,
	   ftp/1,
	   tnt/1,
	   fm/1,
	   tgood/1,
	   fms/1,
	   cFile/1,
	   titFound/1,
	   fpat/1,
	    tnps/2,
	    tnp/1, 
	    outfile/1,
	    mp0/1,
	    mp1/1,
	    mp2/1,
	    mp3/1,
	    mp4/1,
	    mp5/1,
	    mp6/1,
	    mp7/1,
	    bestPen/1,
	    bestSol/1,
	    tempval/1,
	     sum/1 ).

    :- initialization(main).
    main :- 
    argument_value(1, INFILE),!,
    argument_value(2, OUTFILE),!,
    asserta(outfile(OUTFILE)),!,
    getinput(INFILE),!,
    checkHeaders, 
    enumerate,
    %bestSol(X),
    bestPen(Y),
    (Y = 999999
    -> nvp
    ; pvs
    ),
    halt(0).

    getinput(File) :-
    open(File,read,Str),
    readFile(Str, []),
    close(Str).

epf :-
	outfile(X),
	open(X,write,Stream),
	write(Stream,'Error while parsing input file'),
	close(Stream),
	halt(-1).

pvs :-
	outfile(X),
	open(X,write,Stream),
	write(Stream,'Solution '),
	bestSol(S),
	item_at(1,S,A),write(Stream,A), write(Stream,' '),
	item_at(2,S,B),write(Stream,B), write(Stream,' '),
	item_at(3,S,C),write(Stream,C), write(Stream,' '),
	item_at(4,S,D),write(Stream,D), write(Stream,' '),
	item_at(5,S,E),write(Stream,E), write(Stream,' '),
	item_at(6,S,F),write(Stream,F), write(Stream,' '),
	item_at(7,S,G),write(Stream,G), write(Stream,' '),
	item_at(8,S,H),write(Stream,H), write(Stream,'; Quality: '),
	bestPen(Y),write(Stream,Y),
	close(Stream),
	halt(-1).

imt :-
	outfile(X),
	open(X,write,Stream),
	write(Stream,'invalid machine/task'),
	close(Stream),
	halt(-1).

mpe :-
	outfile(X),
	open(X,write,Stream),
	write(Stream,'machine penalty error'),
	close(Stream),
	halt(-1).

ip :-
	outfile(X),
	open(X,write,Stream),
	write(Stream,'invalid penalty'),
	close(Stream),
	halt(-1).

pae :-
	outfile(X),
	open(X,write,Stream),
	write(Stream,'partial assignment error'),
	close(Stream),
	halt(-1).
it :-
	outfile(X),
	open(X,write,Stream),
	write(Stream,'invalid task'),
	close(Stream),
	halt(-1).
nvp :-
	outfile(X),
	open(X,write,Stream),
	write(Stream,'No valid solution possible!'),
	close(Stream),
	halt(-1).


    readFile(Stream, X) :-
    readWord(Stream, Line),
    (Line = ''
     -> readFile(Stream,X)
     ;(Line = 'Name:'
       -> assertz(header(name)), readFile(Stream,X)
       ;(Line = 'forcedpartialassignment:'
	 -> assertz(header(fpa)),dofpas(Stream, X),!
	 ;(Line = 'a'
	   -> !
	   ;(titFound(y)
	     -> epf%write('Error while parsing input file'), halt(-1)
	     ;assertz(titFound(y)), readFile(Stream,X)
	   )
	 )
       )
     )
    ).

   dofpas(Stream, Y) :-
    readWord(Stream, Line),
    %write(Line),nl,
    (Line = ''
     ->dofpas(Stream, Y)
     ;
     (Line = 'forbiddenmachine:'
      -> assertz(header(fm)),dofms(Stream, Y)
      ;  
      (Line = 'a'
       -> !
       ;
       atom_chars(Line, QQ),
       item_at(1, QQ, QQMORE),
       (QQMORE \= '('
	-> epf%write('Error while parsing input file'), halt(-1)
	;
	(validpair(Line)
	 ->atom_chars(Line, F),
	 item_at(2,F,G),
	 item_at(4,F,Q),
	 (fpam(G); fpat(Q)
	  -> pae%write('partial assignment error'),halt(-1)
	  ; 
	  assertz(fpam(G)),assertz(fpat(Q)),assertz(fpa(['(',G,',',Q,')'])),dofpas(Stream,Y)
	 )
	 ;imt%write('invalid machine/task'),halt(-1)
	)
       )
      )
     )
    ).
    
    
   dofms(Stream, Y) :-
    readWord(Stream, Line),
    %write(Line),nl,
    (Line = ''
     ->dofms(Stream, Y)
     ;
     (Line = 'too-neartasks:'
      -> assertz(header(tnt)),dotnts(Stream, Y)
      ;  
      (Line = 'a'
       -> !
       ;
       (validpair(Line)
	-> atom_chars(Line, F), assertz(fm(F)),dofms(Stream,Y)
	;imt%write('invalid machine/task'),halt(-1)
       )
      )
     )
    ).
    
    dotnts(Stream, Y) :-
    readWord(Stream, Line),
    %write(Line),nl,
    (Line = ''
     ->dotnts(Stream, Y)
     ;
     (Line = 'machinepenalties:'
      -> Counter is 0, assertz(header(mp)),domps(Stream, Y, Counter)
      ;  
      (Line = 'a'
       -> !
       ;
       (validtask(Line)
	->atom_chars(Line, F), assertz(tnt(F)),dotnts(Stream,Y)
	;imt%write('tntinvalid machine/task'),halt(-1)
       )
      )
     )
    ).
    
    domps(Stream, Y, Counter) :-
    readWordMp(Stream, Line),
    (Counter = 9
     -> mpe%write('machine penalty error'),halt(-1)
     ;
     (Line = ''
      ->domps(Stream, Y, Counter)
      ;
      (Line = 'too-near penalities:'
       -> epf%write('Error while parsing intput file'), halt(-1)
       ;
       (Line = 'too-near penalities'
	-> assertz(header(tnp)),dotnps(Stream, Y)
	;  
	(Line = 'a'
	 -> !
	 ;
	 atom_codes(Line, LO),
	 split(LO," ", S),
	 length(S, Z),
	 %write(S),nl,
	 (Z = 8
	  -> item_at(1,S,L_ONE), item_at(2,S,L_TWO), item_at(3,S,L_THR), item_at(4,S,L_FOR), item_at(5,S,L_FIV), item_at(6,S,L_SIX), item_at(7,S,L_SEV), item_at(8,S,L_EHT),
	  (isalldigits(L_ONE),isalldigits(L_TWO), isalldigits(L_THR), isalldigits(L_FOR), isalldigits(L_FIV), isalldigits(L_SIX), isalldigits(L_SEV), isalldigits(L_EHT) 
	   -> 
	   number_codes(ONE, L_ONE),number_codes(TWO, L_TWO),number_codes(THR, L_THR),number_codes(FOR, L_FOR),number_codes(FIV, L_FIV),number_codes(SIX, L_SIX),number_codes(SEV, L_SEV),number_codes(EHT, L_EHT),
	   (Counter = 0
	    -> assertz(mp0([ONE,TWO,THR,FOR,FIV,SIX,SEV,EHT])),C is Counter+1,domps(Stream,Y, C)
	    ;(Counter = 1
	      -> assertz(mp1([ONE,TWO,THR,FOR,FIV,SIX,SEV,EHT])),C is Counter+1,domps(Stream,Y, C)
	      ;(Counter = 2
		-> assertz(mp2([ONE,TWO,THR,FOR,FIV,SIX,SEV,EHT])),C is Counter+1,domps(Stream,Y, C)
		;(Counter = 3
		  -> assertz(mp3([ONE,TWO,THR,FOR,FIV,SIX,SEV,EHT])),C is Counter+1,domps(Stream,Y, C)
		  ;
		  (Counter = 4
		   -> assertz(mp4([ONE,TWO,THR,FOR,FIV,SIX,SEV,EHT])),C is Counter+1,domps(Stream,Y, C)
		   ;
		   (Counter = 5
		    -> assertz(mp5([ONE,TWO,THR,FOR,FIV,SIX,SEV,EHT])),C is Counter+1,domps(Stream,Y, C)
		    ;
		    (Counter = 6
		     -> assertz(mp6([ONE,TWO,THR,FOR,FIV,SIX,SEV,EHT])),C is Counter+1,domps(Stream,Y, C)
		     ;(Counter = 7
		       -> assertz(mp7([ONE,TWO,THR,FOR,FIV,SIX,SEV,EHT])),C is Counter+1,domps(Stream,Y, C)
		     )
		    )
		   )
		  )
		)
	      )
	    )
	   )
	   ;length(L_EHT, DD),
	    (DD = 0
	    -> mpe%write('machine penalty error'),halt(-1)
	    ;ip%write('invalid penalty'),halt(-1)
	    )
	  )
	 )
	 ;mpe%write('machine penalty error'),halt(-1)
	)
       )
      )
     )
    ).
    
isalldigits([]) :- fail.
isalldigits(L) :-
	[H|T] = L,
	H >= 48,
	H =< 57,
	isalldigits1(T).
isalldigits1([]) :- !.
isalldigits1(L) :-
	[H|T] = L,
	H >= 48,
	H =< 57,
	isalldigits1(T).

    dotnps(Stream, Y) :-
    readWord(Stream, Line),
    %write(Line),nl,
    (Line = ''
     ->dotnps(Stream, Y)
     ;
     (Line = 'a'
      -> assertz(cFile(done)),!
      ;
      atom_chars(Line, F),
      item_at(2,F,G),
      item_at(4,F,H),
      item_at(6,F,PEN),
      (exists(G),exists(H)
       -> (penexists(PEN)
	   -> atom_chars(Line, F), assertz(tnp(F)),dotnps(Stream,Y)
	   ;ip%write('invalid penalty'),halt(-1)
       )
       ;it%write('invalid task'),halt(-1)
      )
     )
    ).
    
    %code taken from http://swi-prolog.996271.n3.nabble.com/splitting-Lists-based-on-some-delimitor-td902.html

    split(String, "", Result) :- !,
    characters_to_strings(String, Result).
    split(String, Delimiters, Result) :-
    real_split(String, Delimiters, Result).

    characters_to_strings([], []).
    characters_to_strings([C|Cs], [[C]|Ss]) :-
    characters_to_strings(Cs, Ss).

    real_split(String, Delimiters, Result) :-
    (   append(Substring, [Delimiter|Rest], String),
	memberchk(Delimiter, Delimiters)
        ->  Result = [Substring|Substrings],
	real_split(Rest, Delimiters, Substrings)
        ;   Result = [String]
    ).

    %end borrowed code

enumerate:-
    findall(PERM, permutation(['A','B','C','D','E','F','G','H'],PERM), L),
    hardcon(L, 1).

    hardcon(Ls, Counter):-
    item_at(Counter,Ls,I),
    %write(Counter),%nl,
    C is Counter + 1,
    (tnts(I)
     -> (fms(I)
	 -> (fpas(I)
	    -> softcon(I)
	    ; !
	    )
	 ; !
     )
     ; !
    ),
    (C == 40321
     -> !
     ;hardcon(Ls, C)
    ).
    
    

softcon(Item):-
	Z is 0,
	X is 0,
	tnps(Z,Item),
	mach(Item, X),
	tempval(XX),
	sum(ZZ), 
	S is XX + ZZ,
	retract(tempval(XX)),
	retract(sum(ZZ)),
	bestPen(B),
	bestSol(G),
	(S < B
	-> retract(bestPen(B)), asserta(bestPen(S)), retract(bestSol(G)), asserta(bestSol(Item))
	; !
	),
	bestPen(AAA),
	(AAA = 0
	-> pvs
	; !
	).

tnps(Z,Item):-
    asserta(sum(Z)),
    item_at(1,Item,A),
    item_at(2,Item,B),
    (tnp(['(',A,',',B,',',C,')'])
     -> valcon(C,RR),sum(PP), retract(sum(PP)), TT is PP + RR, asserta(sum(TT))
     ; !
     ),
    item_at(2,Item,A1),
    item_at(3,Item,B1),
    (tnp(['(',A1,',',B1,',',C1,')'])
     -> valcon(C1,RR1),sum(PP1), retract(sum(PP1)), TT1 is PP1 + RR1, asserta(sum(TT1))
     ; !
     ),
    item_at(3,Item,A2),
    item_at(4,Item,B2),
    (tnp(['(',A2,',',B2,',',C2,')'])
     -> valcon(C2,RR2),sum(PP2), retract(sum(PP2)), TT2 is PP2 + RR2, asserta(sum(TT2))
     ; !
     ),
    item_at(4,Item,A3),
    item_at(5,Item,B3),
    (tnp(['(',A3,',',B3,',',C3,')'])
     -> valcon(C3,RR3),sum(PP3), retract(sum(PP3)), TT3 is PP3 + RR3, asserta(sum(TT3))
     ; !
     ),
    item_at(5,Item,A4),
    item_at(6,Item,B4),
    (tnp(['(',A4,',',B4,',',C4,')'])
     -> valcon(C4,RR4), sum(PP4), retract(sum(PP4)),TT4 is PP4 + RR4, asserta(sum(TT4))
     ; !
     ),
    item_at(6,Item,A5),
    item_at(7,Item,B5),
    (tnp(['(',A5,',',B5,',',C5,')'])
     -> valcon(C5,RR5), sum(PP5), retract(sum(PP5)),TT5 is PP5 + RR5, asserta(sum(TT5))
     ; !
     ),
    item_at(7,Item,A6),
    item_at(8,Item,B6),
    (tnp(['(',A6,',',B6,',',C6,')'])
     -> valcon(C6,RR6), sum(PP6), retract(sum(PP6)),TT6 is PP6 + RR6, asserta(sum(TT6))
     ; !
     ),
    item_at(8,Item,A7),
    item_at(1,Item,B7),
    (tnp(['(',A7,',',B7,',',C7,')'])
     -> valcon(C7,RR7), sum(PP7), retract(sum(PP7)),TT7 is PP7 + RR7, asserta(sum(TT7))
     ; !
     ).

mach(SOL, X):-
	item_at(1,SOL,A),
	valcon(A,C),
	mp0(L),
	item_at(C,L,P),
	T is X + P,

	item_at(2,SOL,A2),
	valcon(A2,C2),
	mp1(L2),
	item_at(C2,L2,P2),
	O is T + P2,

	item_at(3,SOL,A3),
	valcon(A3,C3),
	mp2(L3),
	item_at(C3,L3,P3),
	K is O + P3,

	item_at(4,SOL,A4),
	valcon(A4,C4),
	mp3(L4),
	item_at(C4,L4,P4),
	B is K + P4,

	item_at(5,SOL,A5),
	valcon(A5,C5),
	mp4(L5),
	item_at(C5,L5,P5),
	D is B + P5,

	item_at(6,SOL,A6),
	valcon(A6,C6),
	mp5(L6),
	item_at(C6,L6,P6),
	J is D + P6,

	item_at(7,SOL,A7),
	valcon(A7,C7),
	mp6(L7),
	item_at(C7,L7,P7),
	S is J + P7,

	item_at(8,SOL,A8),
	valcon(A8,C8),
	mp7(L8),
	item_at(C8,L8,P8),
	JJ is S + P8,
	asserta(tempval(JJ)).

    tnts(Item):-
    item_at(1,Item,A),
    item_at(2,Item,B),
    (tnt(['(',A,',',B,')'])
     -> fail
     ;item_at(2,Item,A1),
     item_at(3,Item,B1),
     (tnt(['(',A1,',',B1,')'])
      -> fail
      ;item_at(3,Item,A2),
      item_at(4,Item,B2),
      (tnt(['(',A2,',',B2,')'])
       -> fail
       ;item_at(4,Item,A3),
       item_at(5,Item,B3),
       (tnt(['(',A3,',',B3,')'])
	-> fail
	;item_at(5,Item,A4),
	item_at(6,Item,B4),
	(tnt(['(',A4,',',B4,')'])
	 -> fail
	 ;item_at(6,Item,A5),
	 item_at(7,Item,B5),
	 (tnt(['(',A5,',',B5,')'])
	  -> fail
	  ;item_at(7,Item,A6),
	  item_at(8,Item,B6),
	  (tnt(['(',A6,',',B6,')'])
	   -> fail
	   ;item_at(8,Item,A7),
	   item_at(1,Item,B7),
	   (tnt(['(',A7,',',B7,')'])
	    -> fail
	    ; !
	   )
	  )
	 )
	)
       )
      )
     )
    ).

    fms(Item):-
    item_at(1,Item,B),
    (fm(['(','1',',',B,')'])
     -> fail
     ;item_at(2,Item,B1),
     (fm(['(','2',',',B1,')'])
      -> fail
      ;item_at(3,Item,B2),
      (fm(['(','3',',',B2,')'])
       -> fail
       ;item_at(4,Item,B3),
       (fm(['(','4',',',B3,')'])
	-> fail
	;item_at(5,Item,B4),
	(fm(['(','5',',',B4,')'])
	 -> fail
	 ;item_at(6,Item,B5),
	 (fm(['(','6',',',B5,')'])
	  -> fail
	  ;item_at(7,Item,B6),
	  (fm(['(','7',',',B6,')'])
	   -> fail
	   ;item_at(8,Item,B7),
	   (fm(['(','8',',',B7,')'])
	    -> fail
	    ; !
	   )
	  )
	 )
	)
       )
      )
     )
    ).


    fpas(Item):-
    item_at(1,Item,B),
    (fpam('1'),fpat(B)
     ->(fpa(['(','1',',',B,')'])%rite(I),nl
	-> !
	; fail
     )
     ;(fpam('1');fpat(B)
       -> fail
       ; !
     )
    ),
    item_at(2,Item,B2),
    (fpam('2'),fpat(B2)
     ->(fpa(['(','2',',',B2,')'])
	-> !
	; fail
     )
     ;(fpam('2');fpat(B2)
       -> fail
       ; !
     )
    ),
    item_at(3,Item,B3),
    (fpam('3'),fpat(B3)
     ->(fpa(['(','3',',',B3,')'])
	-> !
	; fail
     )
     ;(fpam('3');fpat(B3)
       -> fail
       ; !
     )
    ),
    item_at(4,Item,B4),
    (fpam('4'),fpat(B4)
     ->(fpa(['(','4',',',B4,')'])
	-> !
	; fail
     )
     ;(fpam('4');fpat(B4)
       -> fail
       ; !
     )
    ),
    item_at(5,Item,B5),
    (fpam('5'),fpat(B5)
     ->(fpa(['(','5',',',B5,')'])
	-> !
	; fail
     )
     ;(fpam('5');fpat(5)
       -> fail
       ; !
     )
    ),
    item_at(6,Item,B6),
    (fpam('6'),fpat(B6)
     ->(fpa(['(','6',',',B6,')'])
	-> !
	; fail
     )
     ;(fpam('6');fpat(B6)
       -> fail
       ; !
     )
    ),
    item_at(7,Item,B7),
    (fpam('7'),fpat(B7)
     ->(fpa(['(','7',',',B7,')'])
	-> !
	; fail
     )
     ;(fpam('7');fpat(B7)
       -> fail
       ; !
     )
    ),
    item_at(8,Item,B8),
    (fpam('8'),fpat(B8)
     ->(fpa(['(','8',',',B8,')'])
	-> !
	; fail
     )
     ;(fpam('8');fpat(B8)
       -> fail
       ; !
     )
    ).


    readWord(InStream,W):-
    get_code(InStream,Char),
    checkCharAndReadRest(Char,Chars,InStream),
    atom_codes(W,Chars).    
    
    checkCharAndReadRest(10,[],_):-  !.

    checkCharAndReadRest(-1,[97],_):-  !.    

    checkCharAndReadRest(end_of_file,[97],_):-  !.
    
    checkCharAndReadRest(32,Chars,InStream):-
    get_code(InStream,NextChar),
    checkCharAndReadRest(NextChar, Chars,InStream).

    checkCharAndReadRest(9,Chars,InStream):-
    get_code(InStream,NextChar),
    checkCharAndReadRest(NextChar, Chars,InStream).

    checkCharAndReadRest(11,Chars,InStream):-
    get_code(InStream,NextChar),
    checkCharAndReadRest(NextChar, Chars,InStream).

    checkCharAndReadRest(12,Chars,InStream):-
    get_code(InStream,NextChar),
    checkCharAndReadRest(NextChar, Chars,InStream).

    checkCharAndReadRest(13,Chars,InStream):-
    get_code(InStream,NextChar),
    checkCharAndReadRest(NextChar, Chars,InStream).

    checkCharAndReadRest(14,Chars,InStream):-
    get_code(InStream,NextChar),
    checkCharAndReadRest(NextChar, Chars,InStream).

    checkCharAndReadRest(Char,[Char|Chars],InStream):-
    get_code(InStream,NextChar),
    checkCharAndReadRest(NextChar,Chars,InStream). 



    readWordMp(InStream,W):-
    get_code(InStream,Char),
    checkCharAndReadRestMp(Char,Chars,InStream),
    atom_codes(W,Chars).    
    
    checkCharAndReadRestMp(10,[],_):-  !.

    checkCharAndReadRestMp(-1,[97],_):-  !.    

    checkCharAndReadRestMp(end_of_file,[97],_):-  !.
    
    /*checkCharAndReadRest(32,Chars,InStream):-
    get_code(InStream,NextChar),
    checkCharAndReadRest(NextChar, Chars,InStream).*/

    checkCharAndReadRestMp(9,Chars,InStream):-
    get_code(InStream,NextChar),
    checkCharAndReadRestMp(NextChar, Chars,InStream).

    checkCharAndReadRestMp(11,Chars,InStream):-
    get_code(InStream,NextChar),
    checkCharAndReadRestMp(NextChar, Chars,InStream).

    checkCharAndReadRestMp(12,Chars,InStream):-
    get_code(InStream,NextChar),
    checkCharAndReadRestMp(NextChar, Chars,InStream).

    checkCharAndReadRestMp(13,Chars,InStream):-
    get_code(InStream,NextChar),
    checkCharAndReadRestMp(NextChar, Chars,InStream).

    checkCharAndReadRestMp(14,Chars,InStream):-
    get_code(InStream,NextChar),
    checkCharAndReadRestMp(NextChar, Chars,InStream).

    checkCharAndReadRestMp(Char,[Char|Chars],InStream):-
    get_code(InStream,NextChar),
    checkCharAndReadRestMp(NextChar,Chars,InStream).

    checkHeaders :- 
    header(name),
    header(fpa),
    header(fm),
    header(tnt),
    header(mp),
    header(tnp).

    item_at( N, L, Item ) :-
    item_at( N, 0, L, Item ).   
    item_at( N, Count, [H|_], Item ) :-
    CountNew is Count + 1,
    CountNew = N,
    Item = H.
    item_at( N, Count, [_|T], Item ) :-
    CountNew is Count + 1,
    item_at( N, CountNew, T, Item ).

    half(L, Po, Pt):- half(L,L,Po,Pt), !.
    half(Po,[],[],Po).
    half(Po, [_],[],Po).
    half([S|E], [_,_|E2],[S,Po],Pt) :-half(E,E2,Po,Pt).

    validtask('(A,A)').    
    validtask('(B,A)').    
    validtask('(C,A)').    
    validtask('(D,A)').    
    validtask('(E,A)').    
    validtask('(F,A)').    
    validtask('(G,A)').    
    validtask('(H,A)').    
    validtask('(A,B)').    
    validtask('(B,B)').    
    validtask('(C,B)').    
    validtask('(D,B)').    
    validtask('(E,B)').    
    validtask('(F,B)').    
    validtask('(G,B)').    
    validtask('(H,B)').    
    validtask('(A,C)').    
    validtask('(B,C)').    
    validtask('(C,C)').    
    validtask('(D,C)').    
    validtask('(E,C)').    
    validtask('(F,C)').    
    validtask('(G,C)').    
    validtask('(H,C)').    
    validtask('(A,D)').    
    validtask('(B,D)').    
    validtask('(C,D)').    
    validtask('(D,D)').    
    validtask('(E,D)').    
    validtask('(F,D)').    
    validtask('(G,D)').    
    validtask('(H,D)').    
    validtask('(A,E)').    
    validtask('(B,E)').    
    validtask('(C,E)').    
    validtask('(D,E)').    
    validtask('(E,E)').    
    validtask('(F,E)').    
    validtask('(G,E)').    
    validtask('(H,E)').    
    validtask('(A,F)').    
    validtask('(B,F)').    
    validtask('(C,F)').    
    validtask('(D,F)').    
    validtask('(E,F)').    
    validtask('(F,F)').    
    validtask('(G,F)').    
    validtask('(H,F)').    
    validtask('(A,G)').    
    validtask('(B,G)').    
    validtask('(C,G)').    
    validtask('(D,G)').    
    validtask('(E,G)').    
    validtask('(F,G)').    
    validtask('(G,G)').    
    validtask('(H,G)').    
    validtask('(A,H)').    
    validtask('(B,H)').    
    validtask('(C,H)').    
    validtask('(D,H)').    
    validtask('(E,H)').    
    validtask('(F,H)').    
    validtask('(G,H)').    
    validtask('(H,H)').    


    validpair('(1,A)').
    validpair('(2,A)').
    validpair('(3,A)').
    validpair('(4,A)').
    validpair('(5,A)').
    validpair('(6,A)').
    validpair('(7,A)').
    validpair('(8,A)').
    validpair('(1,B)').
    validpair('(2,B)').
    validpair('(3,B)').
    validpair('(4,B)').
    validpair('(5,B)').
    validpair('(6,B)').
    validpair('(7,B)').
    validpair('(8,B)').
    validpair('(1,C)').
    validpair('(2,C)').
    validpair('(3,C)').
    validpair('(4,C)').
    validpair('(5,C)').
    validpair('(6,C)').
    validpair('(7,C)').
    validpair('(8,C)').
    validpair('(1,D)').
    validpair('(2,D)').
    validpair('(3,D)').
    validpair('(4,D)').
    validpair('(5,D)').
    validpair('(6,D)').
    validpair('(7,D)').
    validpair('(8,D)').
    validpair('(1,E)').
    validpair('(2,E)').
    validpair('(3,E)').
    validpair('(4,E)').
    validpair('(5,E)').
    validpair('(6,E)').
    validpair('(7,E)').
    validpair('(8,E)').
    validpair('(1,F)').
    validpair('(2,F)').
    validpair('(3,F)').
    validpair('(4,F)').
    validpair('(5,F)').
    validpair('(6,F)').
    validpair('(7,F)').
    validpair('(8,F)').
    validpair('(1,G)').
    validpair('(2,G)').
    validpair('(3,G)').
    validpair('(4,G)').
    validpair('(5,G)').
    validpair('(6,G)').
    validpair('(7,G)').
    validpair('(8,G)').
    validpair('(1,H)').
    validpair('(2,H)').
    validpair('(3,H)').
    validpair('(4,H)').
    validpair('(5,H)').
    validpair('(6,H)').
    validpair('(7,H)').
    validpair('(8,H)').

    bestPen(999999).
    bestSol(['A','B','C','D','E','F','G','H']).

    exists('A').
    exists('B').
    exists('C').
    exists('D').
    exists('E').
    exists('F').
    exists('G').
    exists('H').

    valcon('A',1).
    valcon('B',2).
    valcon('C',3).
    valcon('D',4).
    valcon('E',5).
    valcon('F',6).
    valcon('G',7).
    valcon('H',8).
    valcon('0',0).
    valcon('1',1).
    valcon('2',2).
    valcon('3',3).
    valcon('4',4).
    valcon('5',5).
    valcon('6',6).
    valcon('7',7).
    valcon('8',8).
    valcon('9',9).
    penexists('0').
    penexists('1').
    penexists('2').
    penexists('3').
    penexists('4').
    penexists('5').
    penexists('6').
    penexists('7').
    penexists('8').
    penexists('9').

    /*number_codes(N,"")*/
    
